package com.photoeditor.demo.model.bean.stash;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;

import com.common.base.ComponentContext;
import com.common.base.utils.DeviceUtils;
import com.photoeditor.R;
import com.photoeditor.demo.model.image.collage.util.MathUtil;
import com.photoeditor.demo.model.image.util.ImageHelper;
import com.photoeditor.demo.model.bean.EditEmojiBean;
import com.photoeditor.demo.ui.widget.stash.container.ContainerView;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import static com.photoeditor.demo.model.bean.EditEmojiBean.RADIUS;
import static com.photoeditor.demo.model.bean.stash.StickerBean.SMALLEST_SIZE;

/**
 * Created by Administrator on 2017/7/5 0005.
 */

public class TimeStickerBean implements ContainerBean {

    public final static float MAX_SIZE = ImageHelper.SCREEN_WIDTH * 1.2f;

    public static final int TYPE_HOUR_SYSTEM_12 = 111;
    public static final int TYPE_HOUR_SYSTEM_24 = 112;
    public static final int TYPE_ELECTRON = 113;

    private Resources mResources = ComponentContext.getContext().getResources();

    private static final float DEFAULT_MARGIN = DeviceUtils.dip2px(ComponentContext.getContext(), 8f);
    private float mMargin = DEFAULT_MARGIN;

    private RectF mRect;

    private RectF mButtonRect;
    private RectF mDeleteRect;

    private RectF mLeftOperationRect;
    private RectF mTopOperationRect;
    private RectF mRightOperationRect;
    private RectF mBottomOperationRect;

    private RectF mLastRectBeforeScale;

    private Matrix mMatrix;

    private Canvas mCanvas;

    private Paint mPaint;

    private float mDegree = 0;
    private float mRealDegree = 0;

    private int mType;
    private int mHour, mMinute, mAmPm;

    private List<Bitmap> mBitmapList = new ArrayList<>();
    private List<RectF> mRectList = new ArrayList<>();

    private Bitmap mBitmap;
    private float mMaxSize;
    private Calendar mCalendar;
    private Matrix mLastMatrix;

    private float mFlipX;
    private float mFlipY;

    public TimeStickerBean(RectF parentRect, int type) {
        this(parentRect, type, Calendar.getInstance());
    }

    public TimeStickerBean(RectF parentRect, int type, Calendar calendar){
        this(parentRect.centerX(), parentRect.centerY(), type, calendar);
    }

    public TimeStickerBean(float centerX, float centerY, int type, Calendar calendar){
        mRect = new RectF();
        mButtonRect = new RectF();
        mDeleteRect = new RectF();
        mLeftOperationRect = new RectF();
        mTopOperationRect = new RectF();
        mRightOperationRect = new RectF();
        mBottomOperationRect = new RectF();
        mLastRectBeforeScale = new RectF();
        mMatrix = new Matrix();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLastRectBeforeScale = new RectF();

        mFlipX = 1;
        mFlipY = 1;

        mType = type;
        mCalendar = calendar;

        initData(centerX, centerY);
    }

    public TimeStickerBean(int type, RectF rect, float degree, int minute, int hour, int hourOfDay, int amPm){
        mRect = new RectF();
        mButtonRect = new RectF();
        mDeleteRect = new RectF();
        mLeftOperationRect = new RectF();
        mTopOperationRect = new RectF();
        mRightOperationRect = new RectF();
        mBottomOperationRect = new RectF();
        mLastRectBeforeScale = new RectF();
        mMatrix = new Matrix();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLastRectBeforeScale = new RectF();

        mFlipX = 1;
        mFlipY = 1;

        mType = type;

        mMinute = minute;
        if (mType == TYPE_HOUR_SYSTEM_12) {
            mHour = hour;
            mAmPm = amPm;
        } else {
            mHour = hourOfDay;
        }
        initBitmap();

        float with = 0, height = 0;
        RectF rectF = null;
        for (int i = 0; i < mBitmapList.size(); i++) {
            Bitmap bitmap = mBitmapList.get(i);
            if(i == 0) {
                height = bitmap.getHeight();
            }
            if (mType == TYPE_HOUR_SYSTEM_12 || mType == TYPE_HOUR_SYSTEM_24) {
                if(i == mBitmapList.size() - 1) {
                    rectF = new RectF(with, height - bitmap.getHeight(), with + bitmap.getWidth(), height);
                    mRectList.add(rectF);
                    with += rectF.width();
                }else {
                    rectF = new RectF(with, 0, with + bitmap.getWidth(), bitmap.getHeight());
                    mRectList.add(rectF);
                    with += (rectF.width() + mMargin);
                }
            }else if(mType == TYPE_ELECTRON){
                if(i == 1){
                    rectF = new RectF(with, 0, with + bitmap.getWidth(), bitmap.getHeight());
                    mRectList.add(rectF);
                    with += (rectF.width() + mMargin * 2);
                }else if(i == mBitmapList.size() - 1){
                    rectF = new RectF(with, 0, with + bitmap.getWidth(), bitmap.getHeight());
                    mRectList.add(rectF);
                    with += rectF.width();
                }else{
                    rectF = new RectF(with, 0, with + bitmap.getWidth(), bitmap.getHeight());
                    mRectList.add(rectF);
                    with += (rectF.width() + mMargin);
                }
            }
        }

        mDegree = degree;
        mRealDegree = mDegree;
        mRect.set(rect);
        countOtherRect();

        mMaxSize = MAX_SIZE;
        mLastRectBeforeScale.set(mRect);

        updateBitmap((int)with, (int)height);
    }

    public TimeStickerBean(int type){
        this(new RectF(), type);
    }

    private void initData(float centerX, float centerY) {
        mMinute = mCalendar.get(Calendar.MINUTE);
        if (mType == TYPE_HOUR_SYSTEM_12) {
            mHour = mCalendar.get(Calendar.HOUR);
            mAmPm = mCalendar.get(Calendar.AM_PM);
        } else {
            mHour = mCalendar.get(Calendar.HOUR_OF_DAY);
        }
        initBitmap();
        float with = 0, height = 0;
        RectF rectF = null;
        for (int i = 0; i < mBitmapList.size(); i++) {
            Bitmap bitmap = mBitmapList.get(i);
            if(i == 0) {
                height = bitmap.getHeight();
            }
            if (mType == TYPE_HOUR_SYSTEM_12 || mType == TYPE_HOUR_SYSTEM_24) {
                if(i == mBitmapList.size() - 1) {
                    rectF = new RectF(with, height - bitmap.getHeight(), with + bitmap.getWidth(), height);
                    mRectList.add(rectF);
                    with += rectF.width();
                }else {
                    rectF = new RectF(with, 0, with + bitmap.getWidth(), bitmap.getHeight());
                    mRectList.add(rectF);
                    with += (rectF.width() + mMargin);
                }
            }else if(mType == TYPE_ELECTRON){
                if(i == 1){
                    rectF = new RectF(with, 0, with + bitmap.getWidth(), bitmap.getHeight());
                    mRectList.add(rectF);
                    with += (rectF.width() + mMargin * 2);
                }else if(i == mBitmapList.size() - 1){
                    rectF = new RectF(with, 0, with + bitmap.getWidth(), bitmap.getHeight());
                    mRectList.add(rectF);
                    with += rectF.width();
                }else{
                    rectF = new RectF(with, 0, with + bitmap.getWidth(), bitmap.getHeight());
                    mRectList.add(rectF);
                    with += (rectF.width() + mMargin);
                }
            }
        }
        mRect.left = centerX - with / 2;
        mRect.top = centerY - height / 2;
        mRect.right = centerX + with / 2;
        mRect.bottom = centerY + height / 2;

        countOtherRect();

        mMaxSize = MAX_SIZE;
        mLastRectBeforeScale.set(mRect);

        updateBitmap((int)with, (int)height);
    }

    public void initRect(RectF parentRect) {
        float width = mRect.width();
        float height = mRect.height();

        mRect.left = parentRect.centerX() - width / 2;
        mRect.top = parentRect.centerY() - height / 2;
        mRect.right = mRect.left + width;
        mRect.bottom = mRect.top + height;

        countOtherRect();

        mLastRectBeforeScale.set(mRect);
    }

    private void updateBitmap(int width, int height) {
        if (mBitmap != null) {
            mBitmap.recycle();
        }
        mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
        for (int i = 0; i < mBitmapList.size(); i++){
            mCanvas.drawBitmap(mBitmapList.get(i), null, mRectList.get(i), mPaint);
        }
    }

    private void initBitmap() {
        if (mType == TYPE_HOUR_SYSTEM_12) {
            if (mHour < 10) {
                mBitmapList.add(getNumBitmap(mHour));
            } else {
                mBitmapList.add(getNumBitmap(mHour / 10));
                mBitmapList.add(getNumBitmap(mHour % 10));
            }
            mBitmapList.add(getColonBitmap());

            mBitmapList.add(getNumBitmap(mMinute / 10));
            mBitmapList.add(getNumBitmap(mMinute % 10));

            mBitmapList.add(getAmPmBitmap());
        } else if (mType == TYPE_HOUR_SYSTEM_24) {
            mBitmapList.add(getNumBitmap(mHour / 10));
            mBitmapList.add(getNumBitmap(mHour % 10));

            mBitmapList.add(getColonBitmap());

            mBitmapList.add(getNumBitmap(mMinute / 10));
            mBitmapList.add(getNumBitmap(mMinute % 10));
        } else if (mType == TYPE_ELECTRON) {
            mBitmapList.add(getNumBitmapElect(mHour / 10));
            mBitmapList.add(getNumBitmapElect(mHour % 10));

            mBitmapList.add(getNumBitmapElect(mMinute / 10));
            mBitmapList.add(getNumBitmapElect(mMinute % 10));
        }
    }


    public int getARType() {
        return mType;
    }

    public int getHour() {
        return mHour;
    }

    public int getMinute() {
        return mMinute;
    }

    public int getAmPm() {
        return mAmPm;
    }

    @Override
    public void setIsTouch(boolean isTouch) {

    }

    @Override
    public boolean isTouch() {
        return false;
    }

    @Override
    public Matrix getMatrix() {
        mMatrix.setRotate(-mDegree, mRect.centerX(), mRect.centerY());
        return mMatrix;
    }

    @Override
    public RectF getRect() {
        return mRect;
    }

    @Override
    public void setDegree(float degree) {
        mRealDegree += degree;
        float remain = mRealDegree % 90;
        if(Math.abs(remain) >= 0 && Math.abs(remain) < 3) {
            this.mDegree = mRealDegree - remain;
        } else if(Math.abs(remain) > 87) {
            if (remain > 0) {
                this.mDegree = mRealDegree + 90 - remain;
            } else {
                this.mDegree = mRealDegree - 90 - remain;
            }
        } else {
            mDegree = mRealDegree;
        }
    }

    @Override
    public float getDegree() {
        return mDegree;
    }

    @Override
    public void dealScaleAndRotation(float downX, float downY, float nowX, float nowY) {
        float px = mRect.centerX();
        float py = mRect.centerY();

        float x1 = downX - px;
        float y1 = downY - py;

        float x2 = nowX - px;
        float y2 = nowY - py;

        float scale = (float) (Math.sqrt(x2 * x2 + y2 * y2) / Math.sqrt(x1 * x1 + y1 * y1));

        double degree1 = MathUtil.getDegree(px, py, downX, downY, px + 1, py);

        double degree2 = MathUtil.getDegree(px, py, nowX, nowY, px + 1, py);

        int location1 = MathUtil.getLocation(x1, y1);
        int location2 = MathUtil.getLocation(x2, y2);

        /**
         * 这里是以px, py作为原点   如果是一二象限则 是逆时针旋转  取负值
         *
         * 如果是三四象限则顺时针角度比较小 取正值
         */
        if (location2 == 1 || location2 == 2) {
            degree2 = -degree2;
        }

        if (location1 == 1 || location1 == 2) {
            degree1 = -degree1;
        }

        double degree = degree2 - degree1;

        setScale(scale);
        setDegree((float) degree);
    }

    @Override
    public void setScale(float scale) {
        Matrix m = new Matrix();
        m.setScale(scale, scale, mRect.centerX(), mRect.centerY());
        RectF rect = new RectF();
        m.mapRect(rect, mRect);
        if(rect.width() >= EditEmojiBean.SMALLEST_SIZE && rect.width() <= mMaxSize) {
            mRect = rect;
            countOtherRect();
            mLastRectBeforeScale.set(mRect);
        }
    }

    @Override
    public void move(float dx, float dy) {
        mRect.offset(dx, dy);
        mButtonRect.offset(dx, dy);
        mDeleteRect.offset(dx, dy);
        mLeftOperationRect.offset(dx, dy);
        mRightOperationRect.offset(dx, dy);
        mTopOperationRect.offset(dx, dy);
        mBottomOperationRect.offset(dx, dy);
        mLastRectBeforeScale.offset(dx, dy);
    }

    @Override
    public void moveTo(RectF lastRectF, float dx, float dy) {
        mRect.left = lastRectF.left - dx;
        mRect.right = lastRectF.right - dx;
        mRect.top = lastRectF.top - dy;
        mRect.bottom = lastRectF.bottom - dy;

        countOtherRect();
    }

    @Override
    public void scaleTo(RectF lastRectF, float scale) {
        Matrix m = new Matrix();
        m.setScale(scale, scale, mRect.centerX(), mRect.centerY());
        m.mapRect(mRect, lastRectF);

        countOtherRect();
    }

    @Override
    public void setLastMatrix(Matrix matrix) {
        if (mLastMatrix == null) {
            mLastMatrix = new Matrix();
        }
        mLastMatrix.set(matrix);
    }

    @Override
    public void doScaleMove(RectF baseRect, RectF supperRect, Matrix matrix, Matrix cacheMatrix, RectF viewRect) {
        if (mLastMatrix == null) {
            RectF dstRect = new RectF();
            RectF a = new RectF(mRect);
            a.offset(-viewRect.left, -viewRect.top);

            //防止坐标对他的影响
            RectF supperRect1 = new RectF(supperRect);
            supperRect1.offset(-viewRect.left, -viewRect.top);
            //aScale是 baseRect -> supperRect的缩放值
            float bScale = supperRect1.width() / baseRect.width();
            Matrix m = new Matrix();
            m.postScale(bScale, bScale, baseRect.centerX(), baseRect.centerY());
            m.postTranslate(supperRect1.centerX() - baseRect.centerX(), supperRect1.centerY() - baseRect.centerY());
            m.invert(m);

            //matrixA是去掉 从baseRect转换到supperRect后的Matrix
            Matrix matrixA = new Matrix(matrix);
            matrixA.preConcat(m);
            matrixA.mapRect(dstRect, a);

            float scale = dstRect.width() / a.width();
            float dx = dstRect.centerX() - a.centerX();
            float dy = dstRect.centerY() - a.centerY();

            cacheMatrix.reset();
            cacheMatrix.setScale(scale, scale, a.centerX(), a.centerY());
            cacheMatrix.mapRect(dstRect, a);

            dstRect.offset(viewRect.left, viewRect.top);
            dstRect.offset(dx, dy);

            if (mRect.width() >= SMALLEST_SIZE && mRect.width() <= mMaxSize) {
                mRect = dstRect;
                countOtherRect();
            }

            mLastMatrix = new Matrix();
            mLastMatrix.set(matrix);
        } else {
            RectF dstRect = new RectF();
            RectF a = new RectF(mRect);
            a.offset(-viewRect.left, -viewRect.top);

            mLastMatrix.invert(mLastMatrix);
            //matrixA是去掉 从baseRect转换到supperRect后的Matrix
            Matrix matrixA = new Matrix(matrix);
            matrixA.preConcat(mLastMatrix);
            matrixA.mapRect(dstRect, a);

            float scale = dstRect.width() / a.width();
            float dx = dstRect.centerX() - a.centerX();
            float dy = dstRect.centerY() - a.centerY();

            cacheMatrix.reset();
            cacheMatrix.setScale(scale, scale, a.centerX(), a.centerY());
            cacheMatrix.mapRect(dstRect, a);

            dstRect.offset(viewRect.left, viewRect.top);
            dstRect.offset(dx, dy);

            if (mRect.width() >= SMALLEST_SIZE && mRect.width() <= mMaxSize) {
                mRect = dstRect;
                countOtherRect();
            }
            mLastMatrix.set(matrix);
        }
    }

    @Override
    public void setDegreeDirect(float degree) {
        this.mDegree = degree;
        mRealDegree = mDegree;
    }

    @Override
    public void setFlip(boolean horizontal, float value) {
        if(horizontal){
            mFlipX = value;
        } else {
            mFlipY = value;
        }
    }

    @Override
    public float getFlipX() {
        return mFlipX;
    }

    @Override
    public float getFlipY() {
        return mFlipY;
    }

    @Override
    public int getType() {
        return ContainerView.BEAN_TYPE_TIME;
    }

    @Override
    public RectF getLastRectBeforeScale() {
        return mLastRectBeforeScale;
    }

    @Override
    public Bitmap getBitmap() {
        return mBitmap;
    }

    @Override
    public void onDestroy() {
        if(mBitmap != null){
            mBitmap.recycle();
        }
        if(mBitmapList != null && mBitmapList.size() > 0){
            for(Bitmap bitmap : mBitmapList){
                bitmap.recycle();
            }
        }
    }

    @Override
    public RectF getButtonRect() {
        return mButtonRect;
    }

    @Override
    public RectF getSettingRect() {
        return null;
    }

    @Override
    public RectF getDeleteRect() {
        return mDeleteRect;
    }

    @Override
    public RectF getLeftOperationRect() {
        return mLeftOperationRect;
    }

    @Override
    public RectF getTopOperationRect() {
        return mTopOperationRect;
    }

    @Override
    public RectF getRightOperationRect() {
        return mRightOperationRect;
    }

    @Override
    public RectF getBottomOperationRect() {
        return mBottomOperationRect;
    }

    @Override
    public void operationLeft(float dx) {

    }

    @Override
    public void operationRight(float dx) {

    }

    @Override
    public void operationTop(float dy) {

    }

    @Override
    public void operationBottom(float dy) {

    }

    private void countOtherRect() {
        mButtonRect.left = mRect.right - RADIUS;
        mButtonRect.top = mRect.bottom - RADIUS;
        mButtonRect.right = mRect.right + RADIUS;
        mButtonRect.bottom = mRect.bottom + RADIUS;

        mDeleteRect.left = mRect.left - RADIUS;
        mDeleteRect.top = mRect.top - RADIUS;
        mDeleteRect.right = mRect.left + RADIUS;
        mDeleteRect.bottom = mRect.top + RADIUS;
    }

    private Bitmap getNumBitmap(int i) {
        switch (i) {
            case 0:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_0);
            case 1:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_1);
            case 2:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_2);
            case 3:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_3);
            case 4:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_4);
            case 5:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_5);
            case 6:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_6);
            case 7:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_7);
            case 8:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_8);
            case 9:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_9);
            default:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_0);
        }
    }

    private Bitmap getNumBitmapElect(int i) {
        switch (i) {
            case 0:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_0);
            case 1:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_1);
            case 2:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_2);
            case 3:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_3);
            case 4:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_4);
            case 5:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_5);
            case 6:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_6);
            case 7:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_7);
            case 8:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_8);
            case 9:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_9);
            default:
                return BitmapFactory.decodeResource(mResources, R.drawable.ic_point_time_0);
        }
    }

    private Bitmap getColonBitmap() {
        return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_point);
    }

    private Bitmap getAmPmBitmap() {
        if (mAmPm == Calendar.AM) {
            return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_am);
        } else if (mAmPm == Calendar.PM) {
            return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_pm);
        }
        return BitmapFactory.decodeResource(mResources, R.drawable.ic_line_time_am);
    }

    public TimeStickerBean deepClone(RectF parentRect){
        return new TimeStickerBean(parentRect, mType, mCalendar);
    }

    public TimeStickerBean deepClone(float centerX, float centerY){
        return new TimeStickerBean(centerX, centerY, mType, mCalendar);
    }
}
